// 12.2.5 默认模板参数
// 默认模板参数（Default Template Arguments）允许我们为模板参数提供默认值，使模板在未指定某些参数时仍能正确实例化。这大大提高了模板的易用性和灵活性。

// 基本语法
// 默认模板参数的语法很直观，只需在参数声明后使用等号指定默认值：
// 类型参数的默认值
template <typename T = int>
class Container
{
    T value;
};

// 非类型参数的默认值
template <typename T, int Size = 10>
class Array
{
    T elements[Size];
};

// 模板模板参数的默认值
template <typename T, template <typename> class Container = std::vector>
class Stack
{
    Container<T> container;
};

// 使用默认参数
// 当使用带有默认参数的模板时，可以省略那些有默认值的参数：
Container<> intContainer;          // T = int（默认值）
Container<double> doubleContainer; // T = double（显式指定）

Array<int> intArray;          // T = int, Size = 10（默认值）
Array<int, 20> largeIntArray; // T = int, Size = 20（显式指定）

// 默认参数的规则
// 默认模板参数有一些重要规则：
// 1.右侧规则：如果一个参数有默认值，那么它右侧的所有参数也必须有默认值
// 正确
template <typename T = int, typename U = double>
class Example1
{
};

// 错误：T有默认值，但其右侧的U没有
template <typename T = int, typename U>
class Example2
{
};

// 2.类模板与函数模板的区别：
// 类模板：从C++11开始，所有模板参数都可以有默认值
// 函数模板：只有尾部的模板参数可以有默认值，且不能通过显式模板参数来使用默认值

// 3.特化与默认参数：
// 特化版本不继承主模板的默认参数
// 特化版本可以有自己的默认参数

// 默认参数的常见用途
// 默认模板参数在多种场景中非常有用：
// 1.容器的分配器：
template <typename T, typename Allocator = std::allocator<T>>
class Vector
{
    // ...
};

// 2.默认策略：
template <typename T, typename Compare = std::less<T>>
class SortedContainer
{
    // ...
};

// 3.默认类型特性：
template <typename T, typename Traits = std::char_traits<T>>
class BasicString
{
    // ...
};

// 4.默认容器类型：
template <typename T, template <typename...> class Container = std::vector>
class Stack
{
    // ...
};

// 默认参数与SFINAE
// 默认参数经常与SFINAE（Substitution Failure Is Not An Error）结合使用，实现条件模板：
// 使用std::enable_if选择不同的实现
template <
    typename T,
    typename = typename std::enable_if<std::is_integral<T>::value>::type>
class OnlyForIntegers
{
    // 只对整型有效的实现
};

// C++20中的改进
// C++20引入了概念（Concepts），使默认参数的约束更加清晰：
template <typename T = int>
    requires std::integral<T>
class IntegralContainer
{
    // ...
};

// 或使用简写形式
template <std::integral T = int>
class IntegralContainer
{
    // ...
};

// 默认模板参数是C++模板系统中的一个重要特性，它使模板更加易用，同时保持了高度的灵活性和定制能力。通过合理设置默认参数，可以大大减少模板使用者的负担，同时不牺牲模板的通用性。
